/**
* Copyright 2020 Huawei Technologies Co., Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at

* http://www.apache.org/licenses/LICENSE-2.0

* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.

* File main.cpp
* Description: dvpp sample main func
*/

#include <iostream>
#include <stdlib.h>
#include <dirent.h>
#include <sys/time.h>

#include "atlas_videocapture.h"
#include "do_process.h"
#include "utils.h"
#include "clipp.h"

using namespace clipp;

AtlasVideoCapture* OpenVideoCapture(std::string input, int listenPort) {
    
    INPUT_MODE mode;           // 输入模式

    // 分别为读摄像头、读Rtsp流、读视频文件、读图片文件夹、接收来自网络的数据
    if (input.empty()) input = "0";  // 无参数默认打开0号相机
    if (IsDigitStr(input)) {
        int cameraId = atoi(input.c_str());
        if ((cameraId < 0) || (cameraId >= CAMERA_ID_INVALID)) {
            ATLAS_LOG_ERROR("Invalid camera id arg %s, only allow %d and %d",
                            input.c_str(), CAMERA_ID_0, CAMERA_ID_1);
            return nullptr;
        }
        mode = CAMERA_INPUT;
    } else if (IsRtspAddr(input)) {
        mode = RTSP_INPUT;
    } else if (IsVideoFile(input)) {
        if (!IsPathExist(input)) {
            ATLAS_LOG_ERROR("The %s is inaccessible", input.c_str());
            return nullptr;
        }
        mode = VIDEO_INPUT;
    } else if (IsDirectory(input)) {
        mode = IMAGE_DIR_INPUT;
    } else if (IsProtocol(input)) {       // 当前只支持UDP和TCP协议
        mode = NETWORK_INPUT;
    } else {
        ATLAS_LOG_ERROR("Invalid param. The arg should be accessible rtsp,"
                        " video file, camera id, image directory, network protocol.");
        return nullptr;
    }
    return new AtlasVideoCapture(input, mode, listenPort);
}

int main(int argc, char *argv[]) 
{  
    // 程序可选运行模式
    enum class mode {work, help};    
    mode selected;

    DoProcess::processParams params;
    params.listenPort = -1;   // 初始化为无效值

    auto workMode = (
        (command("work").set(selected, mode::work) & value("task", params.task) & opt_values("parameters", params.taskParams))
            % "task: dimp, sort, deepsort and retina are supported, parameters: see detailed documentation",
        
         (required("-i", "--input") & value("inputMode", params.input) & opt_value("listenPort", params.listenPort)) 
            % "Support multiple inputs, including image directory, rtsp address, network input(tcp or udp) and video file, enter the listening port when network input is selected, default 12008",

        (option("-o", "--output") & value("format", params.format) & value("destination", params.destination)) 
            % "Support the output of 'network_result' 'network_image', 'image' and 'video', and destination can be local file path or remote network address"
    );

    auto helpMode = (
        command("help").set(selected,mode::help),
        option("-v", "--version").call([]{cout << "version 1.0.24\n\n";}).doc("show version")
    );

    auto cli = workMode | helpMode;

    if(parse(argc, argv, cli)) {
        switch(selected) {
            case mode::work: break;
            case mode::help: 
                cout << make_man_page(cli, "app");
                return 0;
        }
    } else {
        cout << usage_lines(cli, "app") << '\n';
        cout << "error args! type 'app help' lists a help man." << endl;
        return 0;
    }

    

    // 初始化主任务
    auto mainProcess = make_shared<DoProcess>();
    if (ATLAS_OK != mainProcess->Init(params)) {
        ATLAS_LOG_ERROR("init failed");
        return ATLAS_ERROR;
    }

    // 初始化输入，输入初始化不能先于主任务，因为AtlasVideoCapture依赖于ACL，需先进行DoProcess的初始化
    shared_ptr<AtlasVideoCapture> cap(OpenVideoCapture(params.input, params.listenPort));
    if (cap == nullptr) {
        return ATLAS_ERROR;
    }
    
    if(!cap->IsOpened()) {
        ATLAS_LOG_ERROR("Failed to open video");
        return ATLAS_ERROR;
    }

    float average_cost = 0;
    while(1) {
        time_guard t("Loop");
        
        // 读数据
        ImageData image;
        AtlasError ret = cap->Read(image);
        if (ret != ATLAS_OK) {
            break;
        }

        // 处理
        ret = mainProcess->Process(image);
        if (ret != ATLAS_OK) {
            ATLAS_LOG_ERROR("process failed, return %d", ret);
            break;
        }

        // 计时
        if (image.id > 5) {
            average_cost = (average_cost * image.id + t.get()) / (image.id+1.0);
            INFO_LOG("Average Loop time: %fms", average_cost);
        }
    }
    ATLAS_LOG_INFO("Execute sample success");

    return ATLAS_OK;
}
